package anim;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.image.BufferStrategy;
import java.util.Vector;

import anim.animacije.Animacija;
import anim.animacije.Pauza;
import anim.animacije.PremjestiCosH;
import anim.animacije.PremjestiCosV;
import anim.animacije.PremjestiLin;
import anim.animacije.PremjestiNLin;
import anim.animacije.PrikaziObjekat;
import anim.animacije.SakrijObjekat;
import anim.objekti.Objekat;
import anim.objekti.ObojeniNatpis;
import anim.objekti.ObojeniRect;

/**
 * @author Aleksandar Stancic
 */

public class Animator {
	private Canvas canvas = null;
	private Thread anim = null;
	
	private GraphicsEnvironment graphEnv = null;
    private GraphicsDevice graphDevice = null;
    private GraphicsConfiguration graphicConf = null;
    
    private int canW = 0, canH = 0;
    
    private BufferStrategy bufferStrategy = null;
    private Graphics2D graph2D = null; 
    private long interval = 50;
    public static final long POCETNI_INTERVAL = 50;
    
    private Vector<Objekat> objekti = null;
    private Vector<Animacija> animacije = null;
    private int animID = 0;
    
    private float n = 0.0f;
    
    private boolean pauza = false;
    
    private int brPogodaka = 0, brPromasaja = 0;
    private Vector<InfoListener> lis = null;
    
    public Animator(int sirina, int visina)
    {
    	canW = sirina;
    	canH = visina;
    	
    	graphEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
        graphDevice = graphEnv.getDefaultScreenDevice();
        graphicConf = graphDevice.getDefaultConfiguration();
        
        canvas = new Canvas(graphicConf);
        canvas.setPreferredSize(new Dimension(canW, canH));
        canvas.setMinimumSize(new Dimension(canW, canH));
        canvas.setMaximumSize(new Dimension(canW, canH));
        
        //canvas.setIgnoreRepaint(true);
        
        objekti = new Vector<Objekat>();
        animacije = new Vector<Animacija>();
        
        lis = new Vector<InfoListener>();
        
        anim = new Thread(new Runnable() {
			
			@Override
			public void run() {
				long cTime = System.currentTimeMillis();
				while(true)
				{
					crtaj();
					flipuj();
					if(!pauza) azurirajAnimacije();
					
					long nTime = System.currentTimeMillis();
					if(nTime - cTime <= interval)
					{
						try {
							Thread.sleep(interval - (nTime - cTime));
						} catch (InterruptedException e) {
							
						}
					}
					cTime += interval;
				}
			}
		});
        
        animID = 0;
        
        /* TO REMOVE */
        //ObojeniRect or = new ObojeniRect(new Point(-50, -50), new Dimension(50, 50), Color.yellow, Color.green);
        ObojeniNatpis or = new ObojeniNatpis(new Point(-50, -50), new Dimension(50, 50), Color.yellow, Color.green, Color.black, "ABC");
        objekti.add(or);
        
        animacije.add(new Pauza(1500));
        animacije.add(new PremjestiLin(or, new Point(0, 0), 1000));
        animacije.add(new Pauza(2000));
        //animacije.add(new PremjestiNLin(or, new Point(300 - 50, 300 - 50), 2000));
        animacije.add(new PremjestiCosH(or, new Point(300 - 50, 300 - 50), 2000));
        animacije.add(new PremjestiNLin(or, new Point(300 - 50, 0), 2000));
        //animacije.add(new PremjestiNLin(or, new Point(0, 300 - 50), 2000));
        animacije.add(new PremjestiCosV(or, new Point(0, 300 - 50), 2000));
        animacije.add(new PremjestiNLin(or, new Point(0, 0), 2000));
        animacije.add(new Pauza(2000));
        animacije.add(new PremjestiLin(or, new Point(-50, -50), 1000));
        animacije.add(new SakrijObjekat(or));
        /* TO REMOVE */
    }
    
    public void dodajAnimaciju(Animacija a)
    {
    	animacije.add(a);
    }
    
    public void dodajObjekat(Objekat o)
    {
    	objekti.add(o);
    }
    
    public void init()
    {
    	canvas.createBufferStrategy(2);
        bufferStrategy = canvas.getBufferStrategy();
        graph2D = (Graphics2D)bufferStrategy.getDrawGraphics();
    }
    
    public Canvas getCanvas() { return canvas; }
    
    private void crtaj()
    {
    	int x = (int)(Math.sin(n) * 128.0 + 127.0);
    	
    	//graph2D.setBackground(new Color(0, 255 - x, x));
    	//graph2D.setBackground(new Color(0, 0, 64));
    	//graph2D.setBackground(Color.LIGHT_GRAY);
    	graph2D.clearRect(0, 0, canW, canH);
    	
    	n += 0.01f;
    	
    	for(Objekat o : objekti)
    	{
    		if(o.getVidljiv())
    			o.crtaj(graph2D);
    	}
    }
    
    private void flipuj()
    {
    	graph2D.dispose();
    	bufferStrategy.show();
    	graph2D = (Graphics2D)bufferStrategy.getDrawGraphics();
    }
    
    private void azurirajAnimacije()
    {
    	
    	
    	while(animID < animacije.size() && !animacije.get(animID).otkucaj())
    		animID++;
    	
    	if(animID >= animacije.size())
    	{
    		for(InfoListener i : lis)
        	{
        		i.animacijaZavrsena();
        	}
    		pauza = true;
    		return;
    	}
    }
    
    public void kreni()
    {
    	if(!anim.isAlive())
    	{
    		canvas.setIgnoreRepaint(true);
    		anim.start();
    	}
    	else
    		pauza = false;
    }
    
    public void setPauza(boolean p)
    {
    	pauza = p;
    }
    
    public void resetujAnimator()
    {
    	animID = 0;
    	objekti.clear();
    	animacije.clear();
    	
    	for(InfoListener i : lis)
    	{
    		i.osvjeziInformacije(0, 0);
    	}
    }
    
    public void setInfo(int brPog, int brProm)
    {
    	brPogodaka = brPog;
    	brPromasaja = brProm;
    	
    	for(InfoListener i : lis)
    	{
    		i.osvjeziInformacije(brPogodaka, brPromasaja);
    	}
    }
    
    public void dodajInfoListener(InfoListener il)
    {
    	lis.add(il);
    }
    
    public boolean getPauza() { return pauza; }
}
